package com.zml.util;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import sun.misc.BASE64Decoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;

/**
 * @author ye.ming
 */
public class FileAESUtil {

    private static final String KEY = "1234567890123456";

    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
//    Scala语言规范.pdf

    /**
     * init AES Cipher
     *
     * @param passsword
     * @param cipherMode
     * @return
     */
    public static Cipher initAESCipher(String passsword, int cipherMode) {

        Cipher cipher = null;
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            cipher = Cipher.getInstance(ALGORITHMSTR);
            cipher.init(cipherMode, new SecretKeySpec(passsword.getBytes(), "AES"));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvalidKeyException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return cipher;
    }


    /**
     * AES 加密
     *
     * @param originFilePath
     * @param encryptFilePath
     * @param sKey
     * @return
     */
    public static boolean encryptFile(String originFilePath, String encryptFilePath, String sKey) {
        File encryptFile = null;
        File decryptfile = null;
        CipherOutputStream cipherOutputStream = null;
        BufferedInputStream bufferedInputStream = null;
        try {
            encryptFile = new File(originFilePath);
            if (!encryptFile.exists()) {
                throw new NullPointerException("Encrypt file is empty");
            }
            decryptfile = new File(encryptFilePath);
            if (decryptfile.exists()) {
                decryptfile.delete();
            }
            decryptfile.createNewFile();

            Cipher cipher = initAESCipher(sKey, Cipher.ENCRYPT_MODE);
            cipherOutputStream = new CipherOutputStream(new FileOutputStream(decryptfile), cipher);
            bufferedInputStream = new BufferedInputStream(new FileInputStream(encryptFile));

            byte[] buffer = new byte[1024];
            int bufferLength;

            while ((bufferLength = bufferedInputStream.read(buffer)) != -1) {
                cipherOutputStream.write(buffer, 0, bufferLength);
//                encoder.encode(buffer, 0, bufferLength, cipherOutputStream);
            }
            bufferedInputStream.close();
            cipherOutputStream.close();
//            delFile(originFilePath);
        } catch (IOException e) {
            delFile(decryptfile.getAbsolutePath());
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            return false;
        }
        return true;
    }

    /**
     * base 64 encode
     * @param bytes 待编码的byte[]
     * @return 编码后的base 64 code
     */
    public static String base64Encode(byte[] bytes){
        return Base64.encodeBase64String(bytes);
    }

    /**
     * base 64 decode
     * @param base64Code 待解码的base 64 code
     * @return 解码后的byte[]
     * @throws Exception
     */
    public static byte[] base64Decode(String base64Code) throws Exception{
        return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
    }

    /**
     * AES 解密
     *
     * @param originFilePath
     * @param decryptFilePath
     * @param mKey
     * @return
     */

    public static boolean decryptFile(String originFilePath, String decryptFilePath, String mKey) {
        File encryptFile = null;
        File decryptFile = null;
        BufferedOutputStream outputStream = null;
        CipherInputStream inputStream = null;
        try {
            encryptFile = new File(originFilePath);
            if (!encryptFile.exists()) {
                throw new NullPointerException("Decrypt file is empty");
            }
            decryptFile = new File(decryptFilePath);
            if (decryptFile.exists()) {
                decryptFile.delete();
            }
            decryptFile.createNewFile();

            Cipher cipher = initAESCipher(mKey, Cipher.DECRYPT_MODE);

            outputStream = new BufferedOutputStream(new FileOutputStream(decryptFile));
            inputStream = new CipherInputStream(new FileInputStream(encryptFile), cipher);

            int bufferLength;
            byte[] buffer = new byte[1024];

            while ((bufferLength = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bufferLength);
//                encoder.decode(buffer, 0, bufferLength, outputStream);
            }
            inputStream.close();
            outputStream.close();
//            delFile(originFilePath);
        } catch (IOException e) {
            delFile(decryptFile.getAbsolutePath());
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            return false;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }


    /**
     * delete File
     *
     * @param pathFile
     * @return
     */
    public static boolean delFile(String pathFile) {
        boolean flag = false;
        if (pathFile == null && pathFile.length() <= 0) {
            throw new NullPointerException("文件不能为空");
        } else {
            File file = new File(pathFile);
            // 路径为文件且不为空则进行删除
            if (file.isFile() && file.exists()) {
                file.delete();
                flag = true;
            }
        }
        return flag;
    }

    public static String getPath(Scanner scanner) {
        System.out.println("Please input file name in The Path E:/temp/pdf: ");
        return "E:/temp/pdf/" + scanner.nextLine();
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = "";
        String path = getPath(scanner);
        System.out.println("The file path is : " + path);

        while (scanner.hasNextLine()) {
            str = scanner.nextLine();
            if (str.equals("e")) {
                System.out.print("operator result: ");
                String[] paths = path.split("\\.");
                boolean flag = FileAESUtil.encryptFile(path, paths[0] + "_en." + paths[1], KEY);
                System.out.println(flag);
                System.out.println("Please operator way……");
            } else if (str.equals("d")) {
                System.out.print("operator result: ");
                String[] paths = path.split("\\.");
                boolean flag = FileAESUtil.decryptFile(path, paths[0]+"_de." + paths[1], KEY);
                System.out.println(flag);
                System.out.println("Please operator way……");
            } else {
                System.out.println("please input file path again: ");
                path = getPath(scanner);
                System.out.println("Please operator way……");
            }
        }
    }
}
